﻿using NDF.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NDF.Web.Mvc
{
    /// <summary>
    /// 表示一个特性，该特性用于标记在授权期间要跳过指定或所有的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 的控制器和操作。
    /// </summary>
    /// <remarks>
    /// 该特性类似于 <see cref="System.Web.Mvc.AllowAnonymousAttribute"/>，但不同之处在于：
    ///     <see cref="System.Web.Mvc.AllowAnonymousAttribute"/> 指定 Controller 或 Action 跳过所有的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证；
    ///     <see cref="NDF.Web.Mvc.AllowAuthorizeAttribute"/> 指定 Controller 或 Action 可以跳过所有的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证，也可以
    ///     只绕过特定的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证。
    /// 
    /// 当指定的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 类型被添加至该类型实例的 AllowTypes 属性集合中时，<see cref="NDF.Web.Mvc.AllowAuthorizeAttribute"/> 指示
    ///     被标记的 Controller 或 Action 将绕过 AllowTypes 属性指定的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证服务；
    /// 当 AllowTypes 属性不包含任何 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 类型定义元素时，<see cref="NDF.Web.Mvc.AllowAuthorizeAttribute"/> 指示
    ///     被标记的 Controller 或 Action 将绕过所有 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证服务。
    ///     
    /// 注意：要使该标记该特定的 Controller 或 Action 能够有效跳过验证，被添加至 <seealso cref="GlobalFilters.Filters"/> 的所有 AuthorizeAttribute 特性必须
    ///     继承于类型 <see cref="NDF.Web.Mvc.NDFAuthorizeAttribute"/>。
    /// </remarks>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class AllowAuthorizeAttribute : Attribute
    {
        private List<Type> _allowTypes = new List<Type>();


        /// <summary>
        /// 初始化类型 <see cref="NDF.Web.Mvc.AllowAuthorizeAttribute"/> 的新实例。
        /// </summary>
        public AllowAuthorizeAttribute() { }

        /// <summary>
        /// 以指定的 <see cref="System.Type"/> 集合作为可绕过的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证类型初始化类型 <see cref="NDF.Web.Mvc.AllowAuthorizeAttribute"/> 的新实例。
        /// </summary>
        /// <param name="allowTypes">
        /// 一组 <see cref="System.Type"/>，其中每个元素都必须是 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 或其子类；
        /// 表示 Controller 或 Action 可绕过的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证服务。
        /// </param>
        public AllowAuthorizeAttribute(IEnumerable<Type> allowTypes)
        {
            this.CheckAllowTypes(allowTypes);
            this._allowTypes.AddRange(allowTypes);
        }

        /// <summary>
        /// 以指定的 <see cref="System.Type"/> 集合作为可绕过的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证类型初始化类型 <see cref="NDF.Web.Mvc.AllowAuthorizeAttribute"/> 的新实例。
        /// </summary>
        /// <param name="allowTypes">
        /// 一组 <see cref="System.Type"/>，其中每个元素都必须是 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 或其子类；
        /// 表示 Controller 或 Action 可绕过的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证服务。
        /// </param>
        public AllowAuthorizeAttribute(params Type[] allowTypes) : this(allowTypes.AsEnumerable())
        {
        }





        /// <summary>
        /// 获取一个 <see cref="System.Collections.Generic.List(Type)"/> 列表集合属性。该集合中的
        ///     每个 <see cref="System.Type"/> 元素都是 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 类型或其子类，表示一个可以
        ///     在 Controller 或 Action 中被绕过的 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 验证服务。
        /// </summary>
        public Type[] AllowTypes
        {
            get { return this._allowTypes.ToArray(); }
        }



        /// <summary>
        /// 验证 <paramref name="allowTypes"/> 数组中的每个 <paramref name="System.Type"/> 是否都是 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 类型或其子类。
        /// 如果不是，则抛出 <see cref="System.ArgumentException"/> 异常。
        /// </summary>
        /// <param name="allowTypes">一组 <see cref="System.Type"/> 所构成的数组。</param>
        /// <exception cref="System.ArgumentException">
        /// 如果 <paramref name="allowTypes"/> 数组中的每个 <paramref name="System.Type"/> 有任意一个不是 <see cref="NDF.Web.Mvc.AuthorizeAttribute"/> 类型 且不是其子类，则抛出该异常。
        /// </exception>
        protected virtual void CheckAllowTypes(IEnumerable<Type> allowTypes)
        {
            Type baseType = typeof(AuthorizeAttribute);
            foreach (Type type in allowTypes)
            {
                Check.InhertOf(type, baseType);
            }
        }
    }
}
